﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace TAS
{
    public class SecurityTradeDataEntity
    {
        public int Period { get; set; }
        public string SecurityID { get; set; }
        
        //These 2 lists store all OHLC & Bollinger Level Data for the current time period.
        List<BollingerEntity> bollingerLevelsList = new List<BollingerEntity>();
        List<OHLCEntity> ohlcLevelsList = new List<OHLCEntity>();

        List<double> closingValuesList = new List<double>();

        //This the current values of OHLC and BollingerBands.
        BollingerEntity currentBollingerLevel = new BollingerEntity();
        OHLCEntity currentOHLCLevel = new OHLCEntity();

        Logger bollinger_csv = new Logger(), ohlc_csv = new Logger(), combo_csv = new Logger();

        public void Initialize( int period )
        {
            this.Period = period; 
            // added by MS
            currentBollingerLevel.LowerLevel = 0;
            currentBollingerLevel.MiddleLevel = 0;
            currentBollingerLevel.UpperLevel = 0;
            currentOHLCLevel.Open = 0;
            currentOHLCLevel.High = 0;
            currentOHLCLevel.Low = 0;
            currentOHLCLevel.Close = 0;
            this.bollingerLevelsList.Add(currentBollingerLevel);
            this.closingValuesList.Add(0);
            this.ohlcLevelsList.Add(currentOHLCLevel);

            bollinger_csv.Initialize(SecurityID + "_" + period + "_bollinger.csv");
            ohlc_csv.Initialize(SecurityID + "_" + period + "_ohlc.csv");
            combo_csv.Initialize(SecurityID + "_" + period + ".csv");            
        }

        public void UpdateData(TradeDataEntity tradeDataEntity)
        {
            if (currentOHLCLevel == null)
            {
                currentOHLCLevel = new OHLCEntity();
                currentOHLCLevel.Time = tradeDataEntity.Time;
                currentOHLCLevel.Open = tradeDataEntity.Price;
                currentOHLCLevel.High = tradeDataEntity.Price;
                currentOHLCLevel.Low = tradeDataEntity.Price;
                currentOHLCLevel.Close = tradeDataEntity.Price;

                return;
            }

            TimeSpan span = tradeDataEntity.Time.Subtract(currentOHLCLevel.Time);

            if (span.Seconds > this.Period)
            {
                //The new message is outside the time period of the previous trade entry.
                //In this case, push the current OHLC level to the OHLCList
                //Calculate the Bollinger Levels for this 'close' and update to the BollingerList
                //Start a new period in calculation with the current value as the open, high, low and close.

                ohlcLevelsList.Add(currentOHLCLevel);

                if (closingValuesList.Count() == 21)
                {
                    closingValuesList.RemoveAt(0);
                }

                closingValuesList.Add(currentOHLCLevel.Close);

                double average = MathUtils.Average(closingValuesList), standardDeviation = MathUtils.StandardDeviation(closingValuesList);

                BollingerEntity prevBollingerLevel = bollingerLevelsList.Last();

                currentBollingerLevel.UpperLevel = (long)(average + standardDeviation + standardDeviation);
                currentBollingerLevel.MiddleLevel = (long)average;
                currentBollingerLevel.LowerLevel = (long)(average - standardDeviation - standardDeviation);
                currentBollingerLevel.firstDifferential = currentBollingerLevel.MiddleLevel - prevBollingerLevel.MiddleLevel;
                currentBollingerLevel.secondDifferential = currentBollingerLevel.firstDifferential - prevBollingerLevel.firstDifferential;

                bollingerLevelsList.Add(currentBollingerLevel);

                string datetime = tradeDataEntity.Time.Year + "/" + tradeDataEntity.Time.Month + "/" + tradeDataEntity.Time.Day + " " + tradeDataEntity.Time.Hour + ":" + tradeDataEntity.Time.Minute + ":" + tradeDataEntity.Time.Second;

                bollinger_csv.Log(datetime + "," + currentBollingerLevel.LowerLevel + ";" + currentBollingerLevel.MiddleLevel + ";" + currentBollingerLevel.UpperLevel);
                ohlc_csv.Log(datetime + "," + currentOHLCLevel.Open + "," + currentOHLCLevel.Close + "," + currentOHLCLevel.High + "," + currentOHLCLevel.Low);
                combo_csv.Log(datetime + "," + currentOHLCLevel.Open + "," + currentOHLCLevel.Close + "," + currentOHLCLevel.High + "," + currentOHLCLevel.Low + "," + currentBollingerLevel.LowerLevel + ";" + currentBollingerLevel.MiddleLevel + ";" + currentBollingerLevel.UpperLevel);

                currentOHLCLevel = new OHLCEntity();
                currentBollingerLevel = new BollingerEntity();

                currentOHLCLevel.Time = tradeDataEntity.Time;
                currentOHLCLevel.Open = tradeDataEntity.Price;
                currentOHLCLevel.High = tradeDataEntity.Price;
                currentOHLCLevel.Low = tradeDataEntity.Price;
                currentOHLCLevel.Close = tradeDataEntity.Price;
            }
            else
            {
                //The new message falls under the time period of the previos trade entry.
                //In this case, update the OHLC values accordingly.

                if (currentOHLCLevel.High < tradeDataEntity.Price)
                {
                    currentOHLCLevel.High = tradeDataEntity.Price;
                }

                if (currentOHLCLevel.Low > tradeDataEntity.Price)
                {
                    currentOHLCLevel.Low = tradeDataEntity.Price;
                }

                currentOHLCLevel.Close = tradeDataEntity.Price;
            }
        }

        public void LogData ()
        {
            Logger logger = new Logger();
            logger.Initialize("C:\\SecurityTradeData.txt");

            logger.Log(SecurityID);

            if (ohlcLevelsList.Count == 0 && bollingerLevelsList.Count == 0)
            {
                logger.Log("-- No Data for this period " + this.Period + " --");
                logger.Close();
                return;
            }

            logger.Log("Period : " + this.Period + " seconds");

            logger.Log("OHLC Dump");

            foreach (var item in ohlcLevelsList)
            {
                logger.Log(item.Time.ToString() + " : " + item.Open + "," + item.High + "," + item.Low + "," + item.Close);
            }

            logger.Log("Bollinger Bands Dump");

            foreach (var item in bollingerLevelsList)
            {
                logger.Log(item.UpperLevel + "," + item.MiddleLevel + "," + item.LowerLevel);
            }

            logger.Close();
        }

        public OHLCEntity getOHLC()
        {
            return ohlcLevelsList.Last();
        }

        public BollingerEntity getBOLL()
        {
            return bollingerLevelsList.Last();
        }
    }
}
